﻿
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections;
using System.Collections.Generic;
using TomanuExtensions;
using TomanuExtensionsTest.TestClasses;
using System.Linq;
using System.Runtime.CompilerServices;

namespace TomanuExtensionsTest
{
    [TestClass()]
    public class TypeExtensionsTest
    {
        private interface IFalse
        {
        }

        private class MyList : List<int>
        {
        }

        [TestMethod()]
        public void TypeExtensionsTest_IsImplementInterface()
        {
            Assert.IsTrue(new List<int>().GetType().IsImplementInterface(
                typeof(ICollection)));
            Assert.IsFalse(new List<int>().GetType().IsImplementInterface(typeof(IFalse)));
            Assert.IsTrue(typeof(ICollection).IsImplementInterface(typeof(IEnumerable)));
            Assert.IsFalse(typeof(ICollection).IsImplementInterface(typeof(IFalse)));
            Assert.IsTrue(typeof(ICollection).IsImplementInterface(typeof(ICollection)));
            Assert.IsFalse(typeof(IEnumerable).IsImplementInterface(typeof(ICollection)));
            Assert.IsFalse(typeof(IFalse).IsImplementInterface(typeof(ICollection)));
        }

        [TestMethod()]
        public void TypeExtensionsTest_IsDerivedFrom()
        {
            Type t1 = typeof(MyList);
            Type t2 = t1.BaseType;
            Type t3 = typeof(List<int>);

            Assert.IsTrue(typeof(MyList).IsDerivedFrom(typeof(Object)));
            Assert.IsTrue(typeof(MyList).IsDerivedFrom(typeof(List<int>)));
            Assert.IsFalse(typeof(MyList).IsDerivedFrom(typeof(List<short>)));
            Assert.IsFalse(typeof(MyList).IsDerivedFrom(typeof(string)));
        }

        [TestMethod()]
        public void TypeExtensions_GetAllProperties()
        {
            var p1 = typeof(A1).GetAllProperties();
            var p2 = typeof(A2).GetAllProperties();
            var p3 = typeof(A3).GetAllProperties();

            var p1a = p1.Select(p => p + " : " + p.DeclaringType.Name).
                OrderBy(s => s).ToArray();
            var p2a = p2.Select(p => p + " : " + p.DeclaringType.Name).
                OrderBy(s => s).ToArray();
            var p3a = p3.Select(p => p + " : " + p.DeclaringType.Name).
                OrderBy(s => s).ToArray();

            string t1 = String.Join(", ", p1a.Select(s => "\"" + s + "\""));
            string t2 = String.Join(", ", p2a.Select(s => "\"" + s + "\""));
            string t3 = String.Join(", ", p3a.Select(s => "\"" + s + "\""));

            var x1a = new string[] { "Int32 Item [Byte] : A1", "Int32 Item [Int16] : A1", 
                "Int32 Item [Int32] : A1", "Int32 n3 : A1", "Int32 n4 : A1", "Int32 n5 : A1", 
                "Int32 v1 : A1", "Int32 v2 : A1", "Int32 v3 : A1", "Int32 v4 : A1", 
                "Int32 x1 : A1", "Int32 x2 : A1", "Int32 x3 : A1", "Int64 Item [Int64] : A1" };

            var x2a = new string[] { "Int32 a1 : A2", "Int32 a2 : A2", "Int32 Item [Byte] : A1", 
                "Int32 Item [Byte] : A2", "Int32 Item [Int16] : A1", "Int32 Item [Int16] : A2", 
                "Int32 Item [Int32] : A1", "Int32 Item [Int32] : A2", "Int32 n1 : A2", 
                "Int32 n2 : A2", "Int32 n3 : A1", "Int32 n3 : A2", "Int32 n4 : A2", 
                "Int32 n5 : A2", "Int32 v1 : A1", "Int32 v2 : A2", "Int32 v3 : A1", 
                "Int32 v4 : A2", "Int32 v5 : A2", "Int32 v6 : A2", "Int32 x1 : A1", 
                "Int32 x2 : A1", "Int32 x3 : A1", "Int32 x4 : A2", "Int32 x5 : A2", 
                "Int32 x6 : A2", "Int64 Item [Int64] : A2", "UInt64 Item [UInt64] : A2" };

            var x3a = new string[] { "Int32 a1 : A2", "Int32 a2 : A3", "Int32 a3 : A3", 
                "Int32 a4 : A3", "Int32 Item [Byte] : A1", "Int32 Item [Byte] : A2", 
                "Int32 Item [Int16] : A1", "Int32 Item [Int16] : A2", "Int32 Item [Int32] : A1", 
                "Int32 Item [Int32] : A2", "Int32 n1 : A2", "Int32 n1 : A3", "Int32 n2 : A2", 
                "Int32 n2 : A3", "Int32 n3 : A1", "Int32 n3 : A2", "Int32 n3 : A3", 
                "Int32 n4 : A2", "Int32 n4 : A3", "Int32 n5 : A2", "Int32 n5 : A3", 
                "Int32 v1 : A1", "Int32 v2 : A2", "Int32 v3 : A3", "Int32 v4 : A3", 
                "Int32 v5 : A3", "Int32 v6 : A2", "Int32 x1 : A1", "Int32 x2 : A1", 
                "Int32 x3 : A1", "Int32 x4 : A2", "Int32 x5 : A2", "Int32 x6 : A2", 
                "Int32 x7 : A3", "Int32 x8 : A3", "Int32 x9 : A3", "Int64 Item [Int64] : A2", 
                "UInt64 Item [UInt64] : A2" };

            CollectionAssert.AreEqual(p1a, x1a);
            CollectionAssert.AreEqual(p2a, x2a);
            CollectionAssert.AreEqual(p3a, x3a);
        }

        [TestMethod()]
        public void TypeExtensions_GetAllField()
        {
            var f1 = typeof(AC).GetAllFields(true);
            var f2 = typeof(BC).GetAllFields(true);
            var f3 = typeof(AC).GetAllFields();
            var f4 = typeof(BC).GetAllFields();

            var f1a = f1.Select(f => f.Name + "_" + f.DeclaringType.Name).
                OrderBy(s => s).ToArray();
            var f2a = f2.Select(f => f.Name + "_" + f.DeclaringType.Name).
                OrderBy(s => s).ToArray();
            var f3a = f3.Select(f => f.Name + "_" + f.DeclaringType.Name).
                OrderBy(s => s).ToArray();
            var f4a = f4.Select(f => f.Name + "_" + f.DeclaringType.Name).
                OrderBy(s => s).ToArray();

            var x1a = new string[] { "<D>k__BackingField_AC", "<E>k__BackingField_AC", 
                "<F>k__BackingField_AC", "<IP>k__BackingField_AC", "<IP1>k__BackingField_AC", 
                "<IPV>k__BackingField_AC", "<IPV1>k__BackingField_AC", 
                "<IPV2>k__BackingField_AC", "<J>k__BackingField_AC", "<K>k__BackingField_AC", 
                "<L>k__BackingField_AC", "<M>k__BackingField_AC", "<P>k__BackingField_AC", 
                "<Q>k__BackingField_AC", "<R>k__BackingField_AC", "<S>k__BackingField_AC",
                "<T>k__BackingField_AC", "<U>k__BackingField_AC", "A_AC", "B_AC", "C_AC" };

            var x2a = new string[] { "<D>k__BackingField_AC", "<D>k__BackingField_BC", 
                "<D1>k__BackingField_BC", "<E>k__BackingField_AC", "<E>k__BackingField_BC", 
                "<E1>k__BackingField_BC", "<E2>k__BackingField_BC", "<F>k__BackingField_AC", 
                "<F>k__BackingField_BC", "<F2>k__BackingField_BC", "<F3>k__BackingField_BC", 
                "<G>k__BackingField_BC", "<H>k__BackingField_BC", "<IP>k__BackingField_AC", 
                "<IP1>k__BackingField_AC", "<IP1>k__BackingField_BC", "<IP2>k__BackingField_BC", 
                "<IPA>k__BackingField_BC", "<IPA2>k__BackingField_BC", "<IPV>k__BackingField_AC", 
                "<IPV1>k__BackingField_AC", "<IPV1>k__BackingField_BC", 
                "<IPV2>k__BackingField_AC", "<IPV2>k__BackingField_BC", 
                "<IPV3>k__BackingField_BC", "<J>k__BackingField_AC", "<J>k__BackingField_BC", 
                "<K>k__BackingField_AC", "<K>k__BackingField_BC", "<L>k__BackingField_AC", 
                "<M>k__BackingField_AC", "<P>k__BackingField_AC", "<P>k__BackingField_BC", 
                "<Q>k__BackingField_AC", "<Q>k__BackingField_BC", "<R>k__BackingField_AC", 
                "<R>k__BackingField_BC", "<S>k__BackingField_AC", "<S>k__BackingField_BC", 
                "<T>k__BackingField_AC", "<T>k__BackingField_BC", "<U>k__BackingField_AC", 
                "<U>k__BackingField_BC", "A_AC", "A_BC", "A1_BC", "B_AC", "B_BC", "B1_BC", 
                "C_AC", "C_BC", "C1_BC" };

            var x3a = new string[] { "A_AC", "B_AC", "C_AC" };
            var x4a = new string[] { "A_AC", "A_BC", "A1_BC", "B_AC", "B_BC", "B1_BC", 
                "C_AC", "C_BC", "C1_BC" };

            CollectionAssert.AreEqual(f1a, x1a);
            CollectionAssert.AreEqual(f2a, x2a);
            CollectionAssert.AreEqual(f3a, x3a);
            CollectionAssert.AreEqual(f4a, x4a);
        }

        [TestMethod()]
        public void TypeExtensions_GetAllMethods()
        {
            var m1 = typeof(AC).GetAllMethods(true).ToArray();
            var m2 = typeof(BC).GetAllMethods(true).ToArray();
            var m3 = typeof(AC).GetAllMethods().ToArray();
            var m4 = typeof(BC).GetAllMethods().ToArray();

            CollectionAssert.AreEquivalent(
                m1.Where(m => !m.IsDefined(typeof(CompilerGeneratedAttribute), true)).ToList(), 
                m3.ToList());
            CollectionAssert.AreEquivalent(
                m2.Where(m => !m.IsDefined(typeof(CompilerGeneratedAttribute), true)).ToList(),
                m4.ToList());

            var m3a = m3.Select(f => f.Name + "_" + f.DeclaringType.Name).
                OrderBy(s => s).ToArray();
            var m4a = m4.Select(f => f.Name + "_" + f.DeclaringType.Name).
                OrderBy(s => s).ToArray();

            var x3a = new string[] { "Equals_Object", "Finalize_Object", "GetHashCode_Object", 
                "GetType_Object", "MA_new_AC", "MA_only_here_AC", "MA_only_here_AC", 
                "MA_only_here_AC", "MA_only_here_params_AC", "MA_only_here_params_AC", 
                "MA_only_here_params_AC", "MA_only_here_params_AC", "MAA_only_here_params1_AC", 
                "MAA_only_here_params2_AC", "MB_def_params_AC", "MB_new_AC", 
                "MC_virt_only_here_AC", "MC_virt_only_here_params_AC", 
                "MC_virt_only_here_params_AC", "ME_override_AC", "ME_override_AC", 
                "ME_override_AC", "MemberwiseClone_Object", "MG_virt_new_AC", 
                "MG_virt_new_params_AC", "MG_virt_new_params_AC", "MG_virt_new_params_AC", 
                "MH_name_AC", "MK_interface_normal_AC", "MK_interface_virtual_AC", 
                "ToString_Object" };

            var x4a = new string[] { "Equals_Object", "Finalize_Object", "GetHashCode_Object", 
                "GetType_Object", "MA_new_AC", "MA_new_BC", "MA_only_here_AC", "MA_only_here_AC", 
                "MA_only_here_AC", "MA_only_here_params_AC", "MA_only_here_params_AC", 
                "MA_only_here_params_AC", "MA_only_here_params_AC", "MAA_only_here_params1_AC", 
                "MAA_only_here_params2_AC", "MB_def_params_AC", "MB_def_params_BC", "MB_new_AC", 
                "MB_new_BC", "MC_virt_only_here_AC", "MC_virt_only_here_params_AC", 
                "MC_virt_only_here_params_AC", "MD_abstract_BC", "ME_override_BC", 
                "ME_override_BC", "ME_override_BC", "MemberwiseClone_Object", 
                "MF_virt_only_here_BC", "MF_virt_only_here_params_BC", 
                "MF_virt_only_here_params_BC", "MG_virt_new_AC", "MG_virt_new_BC", 
                "MG_virt_new_params_AC", "MG_virt_new_params_AC", "MG_virt_new_params_AC", 
                "MG_virt_new_params_BC", "MG_virt_new_params_BC", "MG_virt_new_params_BC", 
                "MH_name_BC", "MH_only_here_BC", "MH_only_here_BC", "MH_only_here_BC", 
                "MK_interface_abstract_BC", "MK_interface_normal_AC", "MK_interface_virtual_AC", 
                "ML_interface_normal_BC", "ML_interface_virtual_BC", "ToString_Object" };

            CollectionAssert.AreEqual(m3a, x3a);
            CollectionAssert.AreEqual(m4a, x4a);
        }
    }
}
